package com.hyk.commonLib.common.utils;

import android.text.TextUtils;

import androidx.annotation.LongDef;
import androidx.annotation.StringDef;

import org.joda.time.DateTime;
import org.joda.time.DurationFieldType;
import org.joda.time.format.DateTimeFormat;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Locale;
import java.util.regex.Pattern;

/**
 * Created by 贺玉琨 on 2019/3/13.
 */
public class TimeUtils {
    public static final long SECOND_INTERVAL_MINUTE = 60; // 一分钟
    public static final long MINUTE_INTERVAL_HOUR = 60;
    public static final long HOUR_INTERVAL_DAY = 24;
    public static final long DAY_INTERVAL_WEEK = 7;
    public static final long DAY_INTERVAL_YEAR = 365;

    public static final long SECOND_INTERVAL_HOUR = SECOND_INTERVAL_MINUTE * MINUTE_INTERVAL_HOUR; // 一小时
    public static final long SECOND_INTERVAL_DAY = SECOND_INTERVAL_HOUR * HOUR_INTERVAL_DAY; // 一天
    public static final long SECOND_INTERVAL_WEEK = SECOND_INTERVAL_DAY * DAY_INTERVAL_WEEK; // 一周
    public static final long SECOND_INTERVAL_YEAR = SECOND_INTERVAL_DAY * DAY_INTERVAL_YEAR; // 一年

    public static final long MINUTE_INTERVAL_DAY = MINUTE_INTERVAL_HOUR * HOUR_INTERVAL_DAY; // 一天
    public static final long MINUTE_INTERVAL_WEEK = MINUTE_INTERVAL_DAY * DAY_INTERVAL_WEEK; // 一周
    public static final long MINUTE_INTERVAL_YEAR = MINUTE_INTERVAL_DAY * DAY_INTERVAL_YEAR; // 一年

    public static final long HOUR_INTERVAL_WEEK = HOUR_INTERVAL_DAY * DAY_INTERVAL_WEEK; // 一周
    public static final long HOUR_INTERVAL_YEAR = HOUR_INTERVAL_DAY * DAY_INTERVAL_YEAR; // 一年


    @Retention(RetentionPolicy.SOURCE)
    @LongDef({
            SECOND_INTERVAL_MINUTE,
            SECOND_INTERVAL_HOUR,
            SECOND_INTERVAL_DAY,
            SECOND_INTERVAL_WEEK,
            SECOND_INTERVAL_YEAR,
    })
    public @interface TimeInterval {
    }


    public static final String TIME_FORMATTER_FULL = "yyyy-MM-dd HH:mm:ss";
    public static final String TIME_FORMATTER_DATE_ONLY = "yyyy-MM-dd";
    public static final String TIME_FORMATTER_M_D = "MM-dd";
    public static final String TIME_FORMATTER_FULL_IOS_COMPAT = "yyyy/MM/dd HH:mm:ss";
    public static final String TIME_FORMATTER_DATE_ONLY_IOS_COMPAT = "yyyy/MM/dd";
    public static final String TIME_FORMATTER_FULL_IOS_TIME_ZONE = "yyyy-MM-dd'T'HH:mm:ss.SSSZZ";
    public static final String TIME_FORMATTER_DATE_ONLY_IOS_TIME_ZONE = "yyyy-MM-ddZZ";
    public static final String TIME_FORMATTER_FULL_CN = "yyyy年MM月dd日 HH:mm:ss";
    public static final String TIME_FORMATTER_DATE_ONLY_CN = "yyyy年MM月dd日";
    public static final String TIME_FORMATTER_TIME_ONLY = "HH:mm:ss";
    public static final String TIME_FORMATTER_H_M = "HH:mm";
    public static final String TIME_FORMATTER_NO_SEPARATOR = "yyyyMMddHHmmss";
    public static final String TIME_FORMATTER_DATE_ONLY_DOT_SEPARATE = "yyyy.MM.dd";

    @Retention(RetentionPolicy.SOURCE)
    @StringDef(value = {
            TIME_FORMATTER_FULL,
            TIME_FORMATTER_DATE_ONLY,
            TIME_FORMATTER_M_D,
            TIME_FORMATTER_FULL_IOS_COMPAT,
            TIME_FORMATTER_DATE_ONLY_IOS_COMPAT,
            TIME_FORMATTER_FULL_IOS_TIME_ZONE,
            TIME_FORMATTER_DATE_ONLY_IOS_TIME_ZONE,
            TIME_FORMATTER_FULL_CN,
            TIME_FORMATTER_DATE_ONLY_CN,
            TIME_FORMATTER_TIME_ONLY,
            TIME_FORMATTER_H_M,
            TIME_FORMATTER_NO_SEPARATOR,
            TIME_FORMATTER_DATE_ONLY_DOT_SEPARATE,
    }, open = true)
    public @interface TimeFormatter {
    }

    public static long timestamp() {
        return System.currentTimeMillis() / 1000;
    }

    public static long timestampMillis() {
        return System.currentTimeMillis();
    }

    public static String format() {
        return format(timestamp());
    }

    public static String format(long timestamp) {
        return format(timestamp, TIME_FORMATTER_FULL);
    }

    public static String format(@TimeFormatter String timeFormatter) {
        return format(timestamp(), timeFormatter);
    }

    public static String format(long timestamp, @TimeFormatter String timeFormatter) {
        return DateTimeFormat.forPattern(timeFormatter).print(timestamp * 1000);
    }

    public static String formatMillis(long timeMillis) {
        return formatMillis(timeMillis, TIME_FORMATTER_FULL);
    }

    public static String formatMillis(long timeMillis, @TimeFormatter String timeFormatter) {
        return DateTimeFormat.forPattern(timeFormatter).print(timeMillis);
    }

    public static String convert(String timeStr, @TimeFormatter String timeFormatter) {
        return DateTimeFormat.forPattern(timeFormatter).print(str2TimeMillis(timeStr));
    }

    public static long str2Timestamp(String timeStr) {
        return str2TimeMillis(timeStr) / 1000;
    }

    public static long str2TimeMillis(String timeStr) {
        String pattern = getPattern(timeStr);
        if (TextUtils.isEmpty(pattern)) {
            return 0;
        }
        assert pattern != null;
        return DateTime.parse(timeStr, DateTimeFormat.forPattern(pattern)).getMillis();
    }

    public static boolean canRecognizeDateStr(String timeStr) {
        return !TextUtils.isEmpty(getPattern(timeStr));
    }

    private static String getPattern(String timeStr) {
        String pattern = null;
        if (TextUtils.isEmpty(timeStr)) return null;
        if (Pattern.matches("^\\d{4}-\\d{1,2}-\\d{1,2} \\d{2}:\\d{2}:\\d{2}$", timeStr)) {
            pattern = TIME_FORMATTER_FULL;
        } else if (Pattern.matches("^\\d{4}-\\d{1,2}-\\d{1,2}$", timeStr)) {
            pattern = TIME_FORMATTER_DATE_ONLY;
        } else if (Pattern.matches("^\\d{4}/\\d{1,2}/\\d{1,2} \\d{2}:\\d{2}:\\d{2}$", timeStr)) {
            pattern = TIME_FORMATTER_FULL_IOS_COMPAT;
        } else if (Pattern.matches("^\\d{4}/\\d{1,2}/\\d{1,2}$", timeStr)) {
            pattern = TIME_FORMATTER_DATE_ONLY_IOS_COMPAT;
        } else if (Pattern.matches("^\\d{4}-\\d{1,2}-\\d{1,2}T\\d{2}:\\d{2}:\\d{2}.0{3}(Z|[+\\-]\\d{2}:\\d{2})$", timeStr)) {
            pattern = TIME_FORMATTER_FULL_IOS_TIME_ZONE;
        } else if (Pattern.matches("^\\d{4}-\\d{1,2}-\\d{1,2}(Z|[+\\-]\\d{2}:\\d{2})$", timeStr)) {
            pattern = TIME_FORMATTER_DATE_ONLY_IOS_TIME_ZONE;
        } else if (Pattern.matches("^\\d{4}年\\d{1,2}月\\d{1,2}日 \\d{2}:\\d{2}:\\d{2}$", timeStr)) {
            pattern = TIME_FORMATTER_FULL_CN;
        } else if (Pattern.matches("^\\d{4}年\\d{1,2}月\\d{1,2}日$", timeStr)) {
            pattern = TIME_FORMATTER_DATE_ONLY_CN;
        } else if (Pattern.matches("^\\d{14}$", timeStr)) {
            pattern = TIME_FORMATTER_NO_SEPARATOR;
        } else if (Pattern.matches("^\\d{4}\\.\\d{1,2}\\.\\d{1,2}$", timeStr)) {
            pattern = TIME_FORMATTER_DATE_ONLY_DOT_SEPARATE;
        }
        return pattern;
    }

    public static boolean isDateTime1BeforeDateTime2(String dateTime1, String dateTime2) {
        return isDateTime1BeforeDateTime2(str2TimeMillis(dateTime1), str2TimeMillis(dateTime2));
//        DateTimeFormatter dateTimeFormatter = new DateTimeFormatterBuilder().append(ISODateTimeFormat.yearMonthDay()).appendLiteral(' ').append(ISODateTimeFormat.hourMinuteSecond()).toFormatter();
////        DateTimeFormatter dateTimeFormatter = new DateTimeFormatterBuilder().appendLiteral(TIME_FORMATTER_FULL).toFormatter();
//        return DateTime.parse(dateTime1, dateTimeFormatter).compareTo(DateTime.parse(dateTime2, dateTimeFormatter)) < 0;
    }

    public static boolean isDateTime1BeforeDateTime2(long timestampMillis, String dateTime2) {
        return isDateTime1BeforeDateTime2(timestampMillis, str2TimeMillis(dateTime2));
    }

    public static boolean isDateTime1BeforeDateTime2(String dateTime1, long timestampMillis) {
        return isDateTime1BeforeDateTime2(str2TimeMillis(dateTime1), timestampMillis);
    }

    public static boolean isDateTime1BeforeDateTime2(long timestampMillis1, long timestampMillis2) {
        return timestampMillis1 < timestampMillis2;
    }

    public static boolean inToday(String timeStr) {
        if (!canRecognizeDateStr(timeStr)) return false;
        return inToday(str2Timestamp(timeStr));
    }

    public static boolean inToday(long timestamp) {
        long dayBeginTimestamp = new DateTime().secondOfDay().withMinimumValue().getMillis() / 1000;
        long dayEndTimestamp = new DateTime().secondOfDay().withMaximumValue().getMillis() / 1000;
        return dayBeginTimestamp <= timestamp && dayEndTimestamp >= timestamp;
    }

    public static boolean inTomorrow(String timeStr) {
        if (!canRecognizeDateStr(timeStr)) return false;
        return inTomorrow(str2Timestamp(timeStr));
    }

    public static boolean inTomorrow(long timestamp) {
        long dayBeginTimestamp = new DateTime().withFieldAdded(DurationFieldType.days(), 1).secondOfDay().withMinimumValue().getMillis() / 1000;
        long dayEndTimestamp = new DateTime().withFieldAdded(DurationFieldType.days(), 1).secondOfDay().withMaximumValue().getMillis() / 1000;
        return dayBeginTimestamp <= timestamp && dayEndTimestamp >= timestamp;
    }

    public static String formatDuration(long timeMillis) {
        int totalSeconds = (int) (timeMillis / 1000);
        int seconds = totalSeconds % 60;
        int minutes = totalSeconds / 60;
        return String.format(Locale.getDefault(), "%02d:%02d", minutes, seconds);
    }
}
